package org.shangrila.comm.utils;

/* 
 * Copyright (c) 2016, shangrila, All rights reserved. 
 */  
import java.io.UnsupportedEncodingException;
import java.security.Key;  
import java.security.KeyPairGenerator;  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
import java.security.PrivateKey;  
import java.security.PublicKey;  
import java.security.SecureRandom;  
import java.security.Signature;  
  
import javax.crypto.Cipher;  
import javax.crypto.SecretKey;  
import javax.crypto.SecretKeyFactory;  
import javax.crypto.spec.DESKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.logging.Log;  
import org.apache.commons.logging.LogFactory;  
  
/** 
 * 功能简述: 加密解密工具类，对MD5/BASE64/DES/RSA等算法提供了包装. 
 * @author shangrila 
 * @version 1.0 
 */  
public class EncryptUtil {  
    private static Log logger = LogFactory.getLog(EncryptUtil.class);  
      
    private static final int KEY_SIZE = 1024;  
    private static final String  MD5_ALGORITHM= "md5";  
    private static final String  DES_ALGORITHM= "des";  
    private static final String  RSA_ALGORITHM= "rsa";  
    private static final String  SIGNATURE_ALGORITHM= "MD5withRSA";  
   
    private EncryptUtil() {  
    }  
          
    /** 
     * 功能简述: 使用md5进行单向加密. 
     */  
    public static String encryptMD5(String plainText) {  
        byte[] cipherData;
		try {
			cipherData = MessageDigest.getInstance(MD5_ALGORITHM).digest(plainText.getBytes());
	        StringBuilder builder = new StringBuilder();  
	        for(byte cipher : cipherData) {  
	            String toHexStr = Integer.toHexString(cipher & 0xff);  
	            builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr);  
	        }  
	        return builder.toString().toUpperCase();  
		} catch (NoSuchAlgorithmException e) {			
			e.printStackTrace();
		}  
		return null;
    }  
      
    /** 
     * 功能简述: 使用BASE64进行加密. 
     * @param plainData 明文数据 
     * @return 加密之后的文本内容 
     */  
	public static String encryptBASE64(byte[] plainData) {  
        return Base64.encodeBase64String(plainData);  
    }  
      
    /** 
     * 功能简述: 使用BASE64进行解密. 
     * @param cipherText 密文文本 
     * @return 解密之后的数据 
     */  
	public static byte[] decryptBASE64(String cipherText) {  
        return Base64.decodeBase64(cipherText);  
    }  
      
    /** 
     * 功能简述: 使用DES算法进行加密. 
     * @param plainData 明文数据 
     * @param key   加密密钥 
     * @return   
     */  
    public static byte[] encryptDES(byte[] plainData, String key) {  
        return processCipher(plainData, createSecretKey(key), Cipher.ENCRYPT_MODE, DES_ALGORITHM);  
    }  
      
    /** 
     * 功能简述: 使用DES算法进行解密. 
     * @param cipherData    密文数据 
     * @param key   解密密钥 
     * @return 
     */  
    public static byte[] decryptDES(byte[] cipherData, String key) {  
        return processCipher(cipherData, createSecretKey(key), Cipher.DECRYPT_MODE, DES_ALGORITHM);  
    }  
      
    /** 
     * 功能简述: 根据key创建密钥SecretKey. 
     * @param key  
     * @return 
     */  
    private static SecretKey createSecretKey(String key) {  
        SecretKey secretKey = null;  
        try {  
            DESKeySpec keySpec = new DESKeySpec(key.getBytes());  
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);  
            secretKey = keyFactory.generateSecret(keySpec);  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return secretKey;  
    }  
      
    /** 
     * 功能简述: 加密/解密处理流程. 
     * @param processData   待处理的数据 
     * @param key   提供的密钥 
     * @param opsMode   工作模式 
     * @param algorithm   使用的算法 
     * @return   
     */  
    private static byte[] processCipher(byte[] processData, Key key, int opsMode, String algorithm) {  
        try{   
            Cipher cipher = Cipher.getInstance(algorithm);  
            cipher.init(opsMode, key, new SecureRandom());  
            return cipher.doFinal(processData);  
        }  
        catch (Exception e) {  
            logger.error(e);  
        }  
        return null;  
    }  
      
    /** 
     * 功能简述: 创建私钥，用于RSA非对称加密. 
     * @return 
     */  
    public static PrivateKey createPrivateKey() {  
    	 KeyPairGenerator keyPairGenerator;
		try {
			 keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
	         keyPairGenerator.initialize(KEY_SIZE);  
	         return keyPairGenerator.generateKeyPair().getPrivate(); 
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}  
		return null;
    }  
      
    /** 
     * 功能简述: 创建公钥，用于RSA非对称加密. 
     * @return 
     */  
    public static PublicKey createPublicKey() {  
    	try {
	    	KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);  
	        keyPairGenerator.initialize(KEY_SIZE); 
	        return keyPairGenerator.generateKeyPair().getPublic(); 
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} 
    	return null;
    }  
      
    /** 
     * 功能简述: 使用RSA算法加密. 
     * @param plainData 明文数据 
     * @param key   密钥 
     * @return 
     */  
    public static byte[] encryptRSA(byte[] plainData, Key key) {  
        return processCipher(plainData, key, Cipher.ENCRYPT_MODE, RSA_ALGORITHM);  
    }  
      
    /** 
     * 功能简述: 使用RSA算法解密. 
     * @param cipherData    密文数据 
     * @param key   密钥 
     * @return 
     */  
    public static byte[] decryptRSA(byte[] cipherData, Key key) {  
        return processCipher(cipherData, key, Cipher.DECRYPT_MODE, RSA_ALGORITHM);  
    }  
      
    /** 
     * 功能简述: 使用私钥对加密数据创建数字签名. 
     * @param cipherData     已经加密过的数据 
     * @param privateKey    私钥 
     * @return 
     */  
    public static byte[] createSignature(byte[] cipherData, PrivateKey privateKey) {  
        try {  
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(privateKey);  
            signature.update(cipherData);  
            return signature.sign();  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);   
        }  
        return null;  
    }  
      
    /** 
     * 功能简述: 使用公钥对数字签名进行验证. 
     * @param signData  数字签名 
     * @param publicKey 公钥 
     * @return 
     */  
    public static boolean verifySignature(byte[] cipherData, byte[] signData, PublicKey publicKey) {  
        try {  
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(publicKey);  
            signature.update(cipherData);  
            return signature.verify(signData);  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return false;  
    }  
	/**
	 * 字节流数据转为十六进制字符
	 * @param byte[]  		字节流数据
	 * @return String
	 */
	public static String byte2hex(byte[] b) {
		String spliter="";
		String hs = "";
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1)
				hs = hs + "0" + stmp;
			else {
				hs = hs + stmp;
			}
			if (n < b.length - 1) {
				hs = hs + spliter;
			}
		}
		return hs.toUpperCase();
	}
	
    public static void main(String[] args) {
        try {
        	String key = "dfyc_2017";
            String s = "001091000000201000018C8ABB0CEFCD";
            byte[] b = s.getBytes("UTF-8");
            String c = encryptBASE64(b);
            System.out.println("BASE64加密后:" + c);
            byte[] d = decryptBASE64(c);
            System.out.println("BASE64解密后:" + new String(d, "UTF-8"));

            c = encryptMD5(s);
            System.out.println("MD5加密后:" + c); 
            //1327b99abd292c26ce9353dba22e8049
            
            b = encryptDES(b,key);
            System.out.println("DES加密后:" + new String(b, "UTF-8"));
            d = decryptDES(b,key);
            System.out.println("DES解密后:" + new String(d, "UTF-8"));

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}  